﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ExplorerPlus.DomainObjects;
using ExplorerPlus.PersistenceLayer;
using ExplorerPlus.PluginsInterface;
using ExplorerPlus.Utilities;

namespace ExplorerPlus.Tools
{
    public partial class WebImport : Form
    {
        IWebSearchPlugin webSearchPlugin;
        BackgroundWorker addWorker = new BackgroundWorker();

        public WebImport() : this(Categories.Books) { }

        public WebImport(Categories defaultCategory) : this(defaultCategory, "") { }

        public WebImport(Categories defaultCategory, string keyword)
        {
            InitializeComponent();
            this.Text = "Bulk Web Import - Amazon.com";
            this.txtKeyword.Text = keyword;
            addWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoAdd);
            addWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_AddWorkerCompleted);
            addWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
            addWorker.WorkerReportsProgress = true;
        }

        private void WebImport_Load(object sender, EventArgs e)
        {
            List<FlyWeightItem> categories = PersistenceLayerFacade.GetFlyWeightCategories();
            lstCategory.DataSource = categories;
            lstCategory.ValueMember = "Id";
            lstCategory.DisplayMember = "Name";
            lstCategory.SelectedValue = 1;
            DisplayStatus("Ready");
        }

        private void btnSearch_Click(object sender, EventArgs e)
        {
            if (txtKeyword.Text.Trim().Length == 0)
            {
                DisplayError("Please enter search keyword.");
                return;
            }


            if (LoadWebSearchPlugin())
            {
                DisplayStatus("Searching...");
                this.Cursor = Cursors.WaitCursor;
                btnSearch.Enabled = false;
                btnAdd.Enabled = false;
                string[] columns = webSearchPlugin.GetSearchColumns();

                this.SuspendLayout();
                lstItems.SuspendLayout();
                lstItems.Clear();
                foreach (string col in columns)
                {
                    lstItems.Columns.Add(col);
                }
                lstItems.ResizeColumns();
                lstItems.ResumeLayout();
                this.ResumeLayout(false);
                this.PerformLayout();

                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += new DoWorkEventHandler(backgroundWorker_DoSearch);
                worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_SearchWorkerCompleted);
                worker.RunWorkerAsync();

            }
        }

        private void backgroundWorker_DoSearch(object sender, DoWorkEventArgs e)
        {
            // This method will run on a thread other than the UI thread.
            // Be sure not to manipulate any Windows Forms controls created
            // on the UI thread from this method.
            //try
            //{
            List<string[]> results = webSearchPlugin.Search(txtKeyword.Text);
            e.Result = results;
            //}
            //catch (System.ServiceModel.CommunicationException exComm)
            //{
            //    System.Diagnostics.Debug.WriteLine(exComm);
            //    DisplayError("Request timed out. Please make sure you are connected to the internet and try again.");
            //}
            //catch (Exception ex)
            //{
            //    DisplayError("Your request cannot be completed. Error details: " + ex.Message);
            //}
            //finally
            //{
            //    this.Cursor = Cursors.Default;
            //}
        }

        private void backgroundWorker_SearchWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Cursor = Cursors.Default;
            btnSearch.Enabled = true;
            btnAdd.Enabled = true;

            if (e.Error != null)
            {
                if (e.Error is System.ServiceModel.CommunicationException)
                {
                    System.Diagnostics.Debug.WriteLine(e.Error);
                    DisplayError("Request timed out. Please make sure you are connected to the internet and try again.");
                }
                else
                {
                    DisplayError("Your request cannot be completed. Error details: " + e.Error.Message);
                }
                return;
            }

            this.SuspendLayout();
            lstItems.SuspendLayout();
            List<string[]> results = e.Result as List<string[]>;
            foreach (string[] strArr in results)
            {
                ListViewItem item = new ListViewItem();
                item.Text = strArr[0];
                for (int i = 1; i < strArr.Length; i++)
                    item.SubItems.Add(strArr[i]);
                lstItems.Items.Add(item);
            }
            lstItems.ResizeColumns();
            DisplayStatus("Ready");
            lstItems.ResumeLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (webSearchPlugin != null && lstItems.SelectedItems.Count > 0)
            {
                this.Cursor = Cursors.WaitCursor;
                btnSearch.Enabled = false;
                btnAdd.Enabled = false;
                tsProgressBar.Maximum = lstItems.SelectedItems.Count + 1;
                tsProgressBar.Value = 0;
                tsProgressBar.Visible = true;
                DisplayStatus("Downloading items (1 of " 
                    + lstItems.SelectedItems.Count.ToString() + ")");

                List<string[]> keywordsList = new List<string[]>();

                foreach (ListViewItem lvItem in lstItems.SelectedItems)
                {
                    string[] keywords = new string[lstItems.Columns.Count];
                    if (lvItem.SubItems != null && lvItem.SubItems.Count > 0)
                    {
                        for (int i = 0; i < lvItem.SubItems.Count; i++)
                        {
                            keywords[i] = lvItem.SubItems[i].Text;
                        }
                    }
                    keywordsList.Add(keywords);
                }

                addWorker.RunWorkerAsync(keywordsList);
            }
        }

        private void backgroundWorker_DoAdd(object sender, DoWorkEventArgs e)
        {
            List<string[]> keywordsList = e.Argument as List<string[]>;
            List<Item> items = new List<Item>();

            //try
            //{
                for (int i = 0; i < keywordsList.Count; i++)
                {
                    string[] keywords = keywordsList[i];
                    System.Diagnostics.Debug.WriteLine(keywords[0]);
                    Item temp = webSearchPlugin.FindItem(keywords);
                    if (temp != null)
                    {
                        Categories current = (Categories)Enum.Parse(typeof(Categories), temp.CategoryId.ToString());
                        string imagesPath = string.Format("{0}\\Images\\{1}\\",
                            Application.StartupPath, current.ToString());
                        webSearchPlugin.DownloadItemImages(temp, imagesPath);
                        items.Add(temp);
                    }
                    addWorker.ReportProgress(i + 1);
                }
            //}
            //catch (Exception ex)
            //{
            //    System.Diagnostics.Debug.WriteLine(ex);
            //}

            e.Result = items;
        }

        private void backgroundWorker_AddWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Cursor = Cursors.Default;
            btnSearch.Enabled = true;
            btnAdd.Enabled = true;

            if (e.Error != null)
            {
                if (e.Error is System.ServiceModel.CommunicationException)
                {
                    System.Diagnostics.Debug.WriteLine(e.Error);
                    DisplayError("Request timed out. Please make sure you are connected to the internet and try again.");
                }
                else
                {
                    DisplayError("Your request cannot be completed. Error details: " + e.Error.Message);
                }
                tsProgressBar.Visible = false;
                return;
            }

            DisplayStatus("Saving item(s) information");

            List<Item> items = e.Result as List<Item>;

            foreach (Item item in items)
            {
                System.Diagnostics.Debug.WriteLine(item.ItemName);
                Item existingItem = 
                    PersistenceLayerFacade.GetItemByName(item.CategoryId, item.ItemName);
                if (existingItem != null)
                {
                    item.ItemId = existingItem.ItemId;
                }
                
                PersistenceLayerFacade.SaveItem(item);
            }

            tsProgressBar.Value += 1;
            tsProgressBar.Visible = false;

            DisplayStatus("Items added successfully");
        }

        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            tsProgressBar.Value = e.ProgressPercentage;
            DisplayStatus(
                string.Format("Downloading items ({0} of {1})", 
                    e.ProgressPercentage + 1, 
                    lstItems.SelectedItems.Count));
        }

        private bool LoadWebSearchPlugin()
        {
            Plugin info = PersistenceLayerFacade.GetCategoryPlugins((int)lstCategory.SelectedValue);

            object plugin =
                PluginManager.CreateInstance("IWebSearchPlugin", info.WebSearchPlugin);

            if (plugin != null)
            {
                webSearchPlugin = (IWebSearchPlugin)plugin;
                return true;
            }
            else
            {
                DisplayError(lstCategory.Text + " web search plugin is not found.");
                return false;
            }
        }

        private void lstItems_DoubleClick(object sender, EventArgs e)
        {
            if (lstItems.SelectedItems.Count > 0)
            {
                btnAdd_Click(sender, e);
            }
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void DisplayStatus(string message)
        {
            lblStatus.Text = message;
            lblStatus.ForeColor = Color.Black;
        }

        private void DisplayError(string message)
        {
            lblStatus.Text = message;
            lblStatus.ForeColor = Color.Red;
        }

        private void lstCategory_SelectedIndexChanged(object sender, EventArgs e)
        {
            lstItems.Clear();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_SYSKEYDOWN = 0x104;

            if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
            {
                switch (keyData)
                {
                    case Keys.Enter:
                        if (lstItems.Focused)
                        {
                            btnAdd_Click(this, null);
                        }
                        else
                        {
                            btnSearch_Click(this, null);
                        }
                        return true;

                    case Keys.Control | Keys.Q:
                    case Keys.Escape:
                        Application.Exit();
                        return true;
                }
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }
    }
}
